#include <stdio.h>
#include <intrins.h>
#include <string.h>

#include "stc8h.h"
#include "stc32_stc8_usb.h"

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

#define PRINTF_HID            //printf输出直接重定向到USB HID接口


void sys_init(void);
void check_buff();


//#define MAIN_Fosc        22118400L     //定义主时钟
//#define MAIN_Fosc        12000000L     //定义主时钟
//#define MAIN_Fosc        11059200L     //定义主时钟
//#define MAIN_Fosc         5529600L     //定义主时钟
//#define MAIN_Fosc        24000000UL    //定义主时钟
#define MAIN_Fosc        35000000UL     //定义主时钟

//========================================================================
// 函数: void delay_ms(unsigned int ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-3-9
// 备注: 
//========================================================================

u8 data delay_int;

void delay_ms(u8 ms)
{
    do{
        delay_int = MAIN_Fosc / 10000;
        while(--delay_int);
    }while(--ms);
}

void delay_us(u8 ns)
{
    while(ns)
    {
      delay_int = 10;
      while (delay_int) --delay_int;
      --ns;
    }
}
void delay_50(void)
{
    delay_int = 5;
    while (--delay_int);
}

void delay_100(void)
{
    delay_int = 9;
    while (--delay_int);
}

void delay_500(void)
{
    delay_int = 50;
    while (--delay_int);
}



// 数据
// P6 D0-D7
// P7 D8-D15

// 地址
// P0 A0-A7
// P2 A8-A15
// P4 A16-A23
// P10 A24
// P11 A25

// BYTE P13

// OE P14
// CE P15
// WE P16

// MD共计使用 16+21+4=41脚

// MD A1-A21 对应芯片使用 A0-A20 4M





//缓存
#define BUFF_LEN 256

#define BYTE P13
#define OE P14
#define CE P15
#define WE P16
#define RESET P17
#define READY P37


u8 data cmd;
u8 cmdBuffer[20];


u8  data x,y;

u8  data data8;
u16 data data16;
u16 data temp16;
u16 data count16;


//0xF1 设置地址 4字节
u32 data address = 0;
//0xF2 设置缓存 4字节
//最大256
u32 data buff = 128;
//0xF3 设置写入字节长度 1、64、128、256、512 2字节
u32 data writeBuff = 1;
//0xF4 设置读写数据显示顺序，默认1显示 高位+地位
u8 data md_mode = 1;

// 64字节输出使用
u8 data out64[64];

// 临时缓存空间 写入功能缓存待写数据
u8 pageBuffer[BUFF_LEN];//最大256

u8 version[] = "20240612\n\r";





void sys_init()
{
    P_SW2 |= 0x80;//扩展寄存器(XFR)访问使能
    
    P0M0 = 0xff;   P0M1 = 0x00;// A0-7
    P1M0 = 0xff;   P1M1 = 0x00;
    P2M0 = 0xff;   P2M1 = 0x00;// A8-15
    P3M0 = 0x00;   P3M1 = 0x00;
    P4M0 = 0xff;   P4M1 = 0x00;// A16-23
    P5M0 = 0x00;   P5M1 = 0x00;
    P6M0 = 0xff;   P6M1 = 0x00;// D0-D7
    P7M0 = 0xff;   P7M1 = 0x00;// D8-D15

    P3M0 &= ~0x03; P3M1 |= 0x03;    
    
    // P37 输入
    P3M0 &= ~0x80; P3M1 |= 0x80; 

    
    // 地址线0
    P0 = 0;
    P2 = 0;
    P4 = 0;
    P10 = 0;
    P11 = 0;
    
    // 16位模式
    BYTE = 1;
    
    // 
    OE = 1;
    CE = 1;
    WE = 1;
    RESET = 1;
    

    IRC48MCR = 0x80;//使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));//等待时钟稳定
    
    USBCLK = 0x00;
    USBCON = 0x90;
}




// 串口收发 参考 https://www.stcaimcu.com/forum.php?mod=viewthread&tid=2392

u8 char1[1];    // 用于输出
void usb_sendchar(u8 c)
{
  char1[0]=c;
  USB_SendData(char1,1);
  usb_OUT_done();
}    

void usb_send(u8 cs[],u8 length)
{
  USB_SendData(cs,length);
  usb_OUT_done();
}


//读取写入数据缓存
void readBuffer()
{
    uint8_t i;
    while(1){
      if (bUsbOutReady){
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            pageBuffer[i]=UsbOutBuffer[i];
          }
          usb_OUT_done();
          return;
        }
      }
    }
}


void readBuffer128()
{
    uint8_t i;
    while(1){
      if (bUsbOutReady){
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            pageBuffer[i]=UsbOutBuffer[i];
          }
          //usb_OUT_done();
          usb_send("ok\r\n",4);//发送数据 和 usb_OUT_done
          break;
         }
      }
    }
    while(1){
      if (bUsbOutReady){
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            pageBuffer[i+64]=UsbOutBuffer[i];
          }
          //usb_OUT_done();
          usb_send("ok\r\n",4);//发送数据 和 usb_OUT_done
          break;
        }
      }
    }
}


void readBuffer256()
{
    uint8_t i;
    while(1){
      if (bUsbOutReady){
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            pageBuffer[i]=UsbOutBuffer[i];
          }
          //usb_OUT_done();
          usb_send("ok\r\n",4);//发送数据 和 usb_OUT_done
          break;
        }
      }
    }
    while(1){
      if (bUsbOutReady){
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            pageBuffer[i+64]=UsbOutBuffer[i];
          }
          //usb_OUT_done();
          usb_send("ok\r\n",4);//发送数据 和 usb_OUT_done
          break;
        }
      }
    }
    while(1){
      if (bUsbOutReady){
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            pageBuffer[i+128]=UsbOutBuffer[i];
          }
          //usb_OUT_done();
          usb_send("ok\r\n",4);//发送数据 和 usb_OUT_done
          break;
        }
      }
    }
    while(1){
      if (bUsbOutReady){
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            pageBuffer[i+192]=UsbOutBuffer[i];
          }
          //usb_OUT_done();
          usb_send("ok\r\n",4);//发送数据 和 usb_OUT_done
          break;
        }
      }
    }
}


//执行命令缓存
void readCommand(void)
{
    uint8_t i;
    while(1)
    {
      if (bUsbOutReady)
      {
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            cmdBuffer[i]=UsbOutBuffer[i];
          }
          usb_OUT_done();
          return;
        }
      }
    }
}



// ---------------------------------------------------------

/*

GBA - TSOP56

WR      - WE
RD      - OE
CS      - CE
A0-A7   - D0-D7
A8-A15  - D8-D15
A16-A23 - A0-A7
CS2     - BYTE

*/


#define CS2 P13

void GBA_ROM_address_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
    P0M0 = 0xff; P0M1 = 0x00;
}

void GBA_ROM_write_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
    P0M0 = 0xff; P0M1 = 0x00;
}

void GBA_ROM_read_mode(void){
    // 高阻输入
    P6M0 = 0x00; P6M1 = 0xff;
    P7M0 = 0x00; P7M1 = 0xff;
    // 输出
    P0M0 = 0xff; P0M1 = 0x00;
}

void GBA_RAM_write_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
    P0M0 = 0xff; P0M1 = 0x00;
}
void GBA_RAM_read_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
    // 高阻输入
    P0M0 = 0x00; P0M1 = 0xff;
}
//---
void GBA_ROM_address(u32 addr){
    GBA_ROM_write_mode();
    P6 = addr & 0xff;
    P7 = (addr>>8) & 0xff;
    P0 = (addr>>16) & 0xff;
}
void GBA_ROM_read_data(){
    data16 = P7;
    data16 = (data16<<8) | P6;
    //return data16;
    // 数据写入 data16 不需要再返回
}
void GBA_ROM_write_data(u16 d16){
    P7 = (d16>>8) & 0xff;
    P6 = d16 & 0xff;
}
//---
// 读取数据
void GBA_ROM_read(u32 addr){
    GBA_ROM_address(addr);
    CE = 0;
    GBA_ROM_read_mode();
    OE = 0;
    _nop_();
    GBA_ROM_read_data();
    OE = 1;
    CE = 1;
    //return data16;
    // 数据在data16中 无需返回
}
// 写入数据
void GBA_ROM_write(u32 addr, u16 d16){
    GBA_ROM_address(addr);
    _nop_();_nop_();
    CE = 0;
    GBA_ROM_write_data(d16);
    WE = 0;
    _nop_();_nop_();
    WE = 1;
    GBA_ROM_read_mode();
    OE = 0;
    do{
        GBA_ROM_read_data();
    }while(data16 != d16);
    OE = 1;
    CE = 1;
}
// 写命令
void GBA_ROM_write_CMD(u32 addr, u16 d16){
    GBA_ROM_address(addr);
    CE = 0;
    GBA_ROM_write_data(d16);
    WE = 0;
    _nop_();_nop_();
    WE = 1;
    OE = 1;
    CE = 1;
}


// ---------------------------------------------------------




void address_mode(void){
    // 推挽输出
    P0M0 = 0xff; P0M1 = 0x00;
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
}

void read_mode(void){
    // 高阻输入
    P6M0 = 0x00; P6M1 = 0xff;
    P7M0 = 0x00; P7M1 = 0xff;
}

void write_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
}

//读数据
u8 read_byte(){
    // 只读取8位
    return P6;
}
u16 read_word(){
    // MD文件不需要交换输出
    data16 = P7;
    data16 = (data16<<8) | P6;
    return data16;
}

//写数据
void write_word(u16 dat){
    if(md_mode==0){
        // 先高再低
        P7 = (dat>>8) & 0xff;
        P6 = dat & 0xff;
    }else{
        // MD 先高再低
        P6 = (dat>>8) & 0xff;
        P7 = dat & 0xff;
    }
}

void write_word_cmd(u16 dat){
    P6 = dat & 0xff;
    P7 = (dat>>8) & 0xff;
}


void setAddress29(u32 addr) {
    // 地址
    // P0 A0-A7
    // P2 A8-A15
    // P4 A16-A23
    // P10 A24
    // P11 A25
    P0 = addr & 0xff;
    P2 = (addr >> 8) & 0xff;
    P4 = (addr >> 16) & 0xff;
//    P10 = (addr >> 24) & 1;
//    P11 = (addr >> 25) & 1;
}


// 读取数据 每次64字节
void read29(){

    u8 i;

    read_mode();

    WE = 1;
    CE = 1;
    OE = 0;
    for(i=0;i<32;i++){
        setAddress29((address>>1)+i);
        
        CE = 0;
        _nop_();_nop_();
        
        data16 = read_word();
        
        if(md_mode==1){
            // MD先输出高 再输出低
            pageBuffer[(2*i)] = (data16>>8) & 0xff;
            pageBuffer[(2*i)+1] = data16 & 0xff;
        }else{
            // 非MD先低再高
            pageBuffer[(2*i)] = data16 & 0xff;
            pageBuffer[(2*i)+1] = (data16>>8) & 0xff;
        }
        
        CE = 1;
        //_nop_();_nop_();
    }
    OE = 1;

    usb_send(pageBuffer,64);
        
    OE=1;
    CE=1;

    address += 64;
}


void check_buff(){
    u8 i;
    u16 rd;
    read_mode();
    //读数据校验
    WE=1;
    OE=1;
    CE=1;
    delay_500();
    
    for(i=0;i<(buff>>1);i++){
        setAddress29((address>>1)+i);
        //delay_100();
        _nop_();_nop_();
        OE = 0;
        CE = 0;
        //delay_100();
        _nop_();_nop_();
        // 读取数据
        rd = read_word();
        OE = 1;
        CE = 1;
        delay_100();
        
        // 高低位都判断
        if((pageBuffer[(2*i)]==(rd&0xff) && pageBuffer[(2*i)+1]==((rd>>8)&0xff))||
           (pageBuffer[(2*i)+1]==(rd&0xff) && pageBuffer[(2*i)]==((rd>>8)&0xff)) ){
            continue;
        }else{
            usb_send("error\r\n",7);
            return;
        }
    }
    OE=1;
    CE=1;
    usb_send("ok\r\n",4);
}

void write_word29(u32 addr, u16 dat) {
    write_word(dat);
    setAddress29(addr);
    //delay_100();
    _nop_();_nop_();
    CE=0;
    WE=0;
    //delay_us(1);
    //delay_100();
    _nop_();_nop_();
    WE=1;
    CE=1;
    //delay_100();
}

void write_word29_cmd(u32 addr, u16 dat) {
    write_word_cmd(dat);
    setAddress29(addr);
    //delay_100();
    _nop_();_nop_();
    CE=0;
    WE=0;
    //delay_us(1);
    //delay_100();
    _nop_();_nop_();
    WE=1;
    CE=1;
    //delay_100();
}



void write29(){
    u8 i;
    u8 error=0;//是否有错误
    WE=1;
    OE=1;
    CE=1;
    write_mode();
        
    // reset
    if(address == 0){
        write_word29_cmd (0, 0xf0);
        WE=1;
        OE=1;
        CE=1;
        delay_ms(100);
    }
        
    if(buff==256){
      readBuffer256();
    }else if(buff==128){
      readBuffer128();
    }else{
      readBuffer();
    }
  
    
    //delay_ms(1);
    // page 写入
    if(writeBuff > 1){
        write_word29_cmd (0x5555, 0xaa);
        write_word29_cmd (0x2aaa, 0x55);
        write_word29_cmd (0x5555, 0xa0);
        for(i=0;i<(buff>>1);i++){
            data16 = pageBuffer[(2*i)+1];
            data16 = (data16<<8) | pageBuffer[(2*i)];
            write_word29((address>>1)+i,data16);
            //delay_100();
        }
        delay_ms(10);
    }else{
        // 错误计数器
        error = 0;
        // 单字节写入  
        for(i=0;i<(buff>>1);i++){
            write_mode();
            data16 = pageBuffer[(2*i)+1];
            data16 = (data16<<8) | pageBuffer[(2*i)];
            write_word29_cmd (0x5555, 0xaa);
            write_word29_cmd (0x2aaa, 0x55);
            write_word29_cmd (0x5555, 0xa0);
            write_word29((address>>1)+i,data16);
            //delay_100();
            read_mode();
            count16 = 0;
            do{
                OE = 0;
                CE = 0;
                temp16 = read_word();
                OE = 1;
                CE = 1;
                if (temp16!=data16)
                    delay_us(1);
                else
                    break;
            }while( ++count16 < 500);
            
            if (count16>=500){
                error = 1;
                break;
            }
        }
    }

    CE=1;
    OE=1;
    WE=1;
    //delay_us(1);
    //delay_500();
    //read_mode();
  
  
  
//    if(address<8192){
//        delay_ms(1);
//        check_buff();
//        //check方法返回ok
//    }else{
//        usb_send("ok\r\n",4);    
//    }
    
    if(error==0){
        usb_send("ok\r\n",4);
    }else{
        usb_send("error\r\n",7);
    }
    
  
    // 返回前更新地址
    address += buff;
    //setAddress(0);
    //delay_us(1);
}



void erase29(){
    write_mode();
    RESET = 0;
    WE=1;
    CE=1;
    OE=1;
    delay_500();
    RESET = 1;
    delay_500();

    write_word29_cmd (0x5555, 0xaa);
    write_word29_cmd (0x2aaa, 0x55);
    write_word29_cmd (0x5555, 0x80);
    write_word29_cmd (0x5555, 0xaa);
    write_word29_cmd (0x2aaa, 0x55);
    write_word29_cmd (0x5555, 0x10);

    CE=1;
    delay_ms(100);
    usb_send("ok\r\n",4);
}


void lock29(){
    WE=1;
    OE=1;
    CE=0;
    write_mode();
    write_word29_cmd (0x5555, 0xaa);
    write_word29_cmd (0x2aaa, 0x55);
    write_word29_cmd (0x5555, 0xa0);
    CE=1;
    read_mode();
    //delay_500();
    usb_send("ok\r\n",4);
}

void unlock29(){
    WE=1;
    OE=1;
    CE=0;
    write_mode();
    write_word29_cmd (0x5555, 0xaa);
    write_word29_cmd (0x2aaa, 0x55);
    write_word29_cmd (0x5555, 0x80);
    write_word29_cmd (0x5555, 0xaa);
    write_word29_cmd (0x2aaa, 0x55);
    write_word29_cmd (0x5555, 0x20);
    CE=1;
    WE=1;
    read_mode();
    //delay_500();
    usb_send("ok\r\n",4);
}



void main()
{
    sys_init();                                     //管脚初始化
    usb_init();                                     //USB CDC 接口配置
    
    IE2 |= 0x80;                                    //使能USB中断
    EA = 1;                                         //总中断控制打开
      
    read_mode();
    
    while (DeviceState != DEVSTATE_CONFIGURED);     //等待USB完成配置

    while (1) {
            
        readCommand();
            
        cmd    = cmdBuffer[0];
        
        switch(cmd){

            //case 'i':
            case 0x02:
                usb_send("MD-STC\r\n",15);
                break;
            //case 'v':
            case 0x03:
                usb_send(version,10);
                break;
            //case 't':
            case 0x04:
                usb_send("ok\r\n",4);
                break;
            
            
            
            // GBA 读取rom
            case 0x20:
                
                CS2 = 1;
                GBA_ROM_address_mode();
                for(x=0;x<32;x++){
                    GBA_ROM_read(address+x);
                    pageBuffer[(2*x)] = data16 & 0xff;
                    pageBuffer[(2*x)+1] = (data16>>8) & 0xff;
                }
                usb_send(pageBuffer,64);
                address += 32;
                
                break;
                
            // 读取ID    
            case 0x21:
                
                CS2 = 1;
                GBA_ROM_address_mode();
                GBA_ROM_write_CMD(0x5555, 0xaa);
                GBA_ROM_write_CMD(0x2aaa, 0x55);
                GBA_ROM_write_CMD(0x5555, 0x90);
//                GBA_ROM_read(0x0);
//                pageBuffer[0] = (data16>>8) & 0xff;
//                pageBuffer[1] = data16 & 0xff;
//                GBA_ROM_read(0x1);
//                pageBuffer[2] = (data16>>8) & 0xff;
//                pageBuffer[3] = data16 & 0xff;
//                usb_send(pageBuffer, 4);
    
                GBA_ROM_read(0x0);
                pageBuffer[0] = data16 & 0xff;
                GBA_ROM_read(0x1);
                pageBuffer[1] = data16 & 0xff;
            
                // 退出
                GBA_ROM_write_CMD(0x5555, 0xaa);
                GBA_ROM_write_CMD(0x2aaa, 0x55);
                GBA_ROM_write_CMD(0x5555, 0xf0);
            
                usb_send(pageBuffer, 2);
                break;
                            
            //case 'r':
            case 0xA1:
                read29();
                break;

            //case 'w':
            case 0xB1:
                write29();
                break;
                
                
            // 擦除
            //case 'e':
            case 0xC1:
                erase29();
                delay_ms(250);
                break;
                
            //case 'l':
            case 0xD1:
                lock29();
                break;

            //case 'u':
            case 0xD2:
                unlock29();
                break;

            // 地址 address
            case 0xE1:
                //address = cmdBuffer[1]<<24 + cmdBuffer[2]<<16 + cmdBuffer[3]<<8 + cmdBuffer[4];
                address = cmdBuffer[1];
                address = (address<<8) | cmdBuffer[2];
                address = (address<<8) | cmdBuffer[3];
                address = (address<<8) | cmdBuffer[4];
                usb_send("ok\r\n",4);
                break;
            // 设置缓存长度
            case 0xE2:
                
                buff = cmdBuffer[1];
                buff = (buff<<8) | cmdBuffer[2];
                buff = (buff<<8) | cmdBuffer[3];
                buff = (buff<<8) | cmdBuffer[4];
            
                //buff = cmdBuffer[4];
                usb_send("ok\r\n",4);
                break;
            // 设置写入缓存长度 1 128 256 512 1是单字节写入 其他是page写入
            case 0xE3:
            
                writeBuff = cmdBuffer[3];
                writeBuff = (writeBuff<<8) | cmdBuffer[4];
                usb_send("ok\r\n",4);
                break;
            
            // 设置读写方式，MD默认1 高位+低位。8位模式 低位+高位
            case 0xE4:
                md_mode = cmdBuffer[4]==0?0:(cmdBuffer[4] & 0xff);
            
                if(md_mode==0 || md_mode==1){
                    address_mode();
                }
            
                usb_send("ok\r\n",4);
                break;
            
            
            
            // 测试用 返回缓存数据
            case 0xE9:
                readBuffer();
                for(data8=0;data8<64;data8++){
                    usb_sendchar(pageBuffer[data8]);
                }
                break;
                
                
                

            case 0xF1:
                usb_send((address<0xf1?"a":"b"),1);
                usb_send("\r\n",2);
                break;
            case 0xF2:
                usb_send((buff==128?"a":"b"),1);
                usb_send("\r\n",2);
                break;
            case 0xF3:
                usb_send(writeBuff==1?"x":"y",1);
                usb_send("\r\n",2);
                break;
                
            default:    break;

        }
        
        WE = 1;
        OE = 1;
        CE = 1;
        
        setAddress29(0);
    }
}


